// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.


// FILE:      AsyncRPCp.c
//
// PURPOSE:   Remote procedures that are linked with the server
//            side of RPC distributed application
//
// COMMENTS:  The Microsoft RPC AsyncRPC sample program demonstrates
//            the use of the [async] attribute and the related asynchronous
//            RPC API functions. The asynchronous function will take certain
//            amount of time to finish. In the process, it also periodically
//            checks whether the call has been cancelled by the client. 
//            For more information, see MSDN online reference.
//
//

#include <stdlib.h>
#include <stdio.h>
#include "AsyncRPC.h" // header file generated by MIDL compiler

const char PERCENT = '%';
const unsigned long DEFAULT_NONASYNC_DELAY     = 1000;  // in miliseconds
const unsigned long ASYNC_CANCEL_CHECK         = 500;   // in miliseconds

// Non-asynchronous routine which can be called
// by a client when an asynchronous routine is running.
void NonAsyncFunc(IN RPC_BINDING_HANDLE hBinding,
                  IN unsigned char * pszMessage)
{
   Sleep(DEFAULT_NONASYNC_DELAY);
   fprintf_s(stderr, "\n\nReceived (%s) via NonAsyncFunc\n\n", pszMessage);
}


// Asynchronous routine. It sends back the notification
// when it is done.
void AsyncFunc(IN PRPC_ASYNC_STATE pAsync,
               IN RPC_BINDING_HANDLE hBinding,
               IN unsigned long nAsychDelay)
{
   int nReply = 1;
   RPC_STATUS status;
   unsigned long nTmpAsychDelay;
   int i;

   if (nAsychDelay < 0)
      nAsychDelay = DEFAULT_ASYNC_DELAY;

   nAsychDelay *= 1000;  // convert to ms

   // We only call RpcServerTestCancel if the call
   // takes longer than ASYNC_CANCEL_CHECK ms
   if (nAsychDelay > ASYNC_CANCEL_CHECK)
   {
      nTmpAsychDelay = nAsychDelay/100;

      for (i = 0; i < 100; i++)
      {
         Sleep(nTmpAsychDelay);

         if (i%5 == 0)
         {
            // Report the progress of the asynchronous function
            fprintf_s(stderr, "\rRunning AsyncFunc (%lu ms) (%d%c) ... ",
                    nAsychDelay, i+5, PERCENT);

            // Check whether the call is cancelled by the client
            status = RpcServerTestCancel(RpcAsyncGetCallHandle(pAsync));
            if (status == RPC_S_OK)
            {
               fprintf_s(stderr, "\nAsyncFunc has been cancelled!!!\n");
               break;
            }
            else if (status != RPC_S_CALL_IN_PROGRESS)
            {
               printf_s("RpcServerTestCancel returned 0x%x\n", status);
               exit(status); 
            }
         }
      }
   }
   else
      Sleep(nAsychDelay);

   printf_s("\nCalling RpcAsyncCompleteCall\n");
   status = RpcAsyncCompleteCall(pAsync, &nReply);
   printf_s("RpcAsyncCompleteCall returned 0x%x\n", status);
   if (status)
      exit(status);
}


void Shutdown(IN RPC_BINDING_HANDLE hBinding)
{
   RPC_STATUS status;

   printf_s("Calling RpcMgmtStopServerListening\n");
   status = RpcMgmtStopServerListening(NULL);
   printf_s("RpcMgmtStopServerListening returned: 0x%x\n", status);
   if (status)
      exit(status);

   printf_s("Calling RpcServerUnregisterIf\n");
   status = RpcServerUnregisterIf(NULL, NULL, FALSE);
   printf_s("RpcServerUnregisterIf returned 0x%x\n", status);
   if (status)
      exit(status);
}
